﻿using System;
using System.Collections.Generic;
using ReAnimation.Domain;
using ReAnimation.Helpers.Common;
using ReAnimation.Helpers.WinForms;
using ReAnimation.MVP.Models.Interfaces;
using ReAnimation.Helpers.DynamicProxy;


namespace ReAnimation.MVP.Models
{
    public class MainModel: IMainModel
    {
        private Molecule _currentMolecule = null;
        private Animation _currentAnimation = null;
        private AnimationStep _currentAnimationStep = null;

        public Animation CurrentAnimation
        {
            get { return _currentAnimation; }
            set
            {
                if (_currentAnimation != value)
                {
                    if (_currentAnimation != null)
                        EventsSource.EditSubscriptionsFor(_currentAnimation).ClearSubscriptions();

                    _currentAnimation = value;

                    EventsSource.EditSubscriptionsFor(_currentAnimation).
                        AfterPropertySet(() => _currentAnimation.AnimationSteps).
                        AfterMethodCall<AnimationStep>((a) => _currentAnimation.AddAnimationStep(null)).
                        AfterMethodCall<AnimationStep>((a) => _currentAnimation.RemoveAnimationStep(null)).
                        Handler(() => { CurrentAnimationStepsChanged.Throw(this, EventArgs.Empty); });

                    CurrentAnimationChanged.Throw(this, EventArgs.Empty);
                }
            }
        }

        public AnimationStep CurrentAnimationStep
        {
            get
            {
                return _currentAnimationStep;
            }
            set
            {
                if (_currentAnimationStep == value) return; 
                if(_currentAnimationStep != null)
                    EventsSource.EditSubscriptionsFor(_currentAnimationStep).ClearSubscriptions();

                _currentAnimationStep = value;

                if (_currentAnimationStep != null)
                {
                    EventsSource.EditSubscriptionsFor(_currentAnimationStep).
                        AfterPropertySet(() => _currentAnimationStep.Percent).
                        Handler(() => { CurrentAnimationStepPercentChanged.Throw(this, EventArgs.Empty); });

                    EventsSource.EditSubscriptionsFor(_currentAnimationStep).
                        AfterPropertySet(() => _currentAnimationStep.Molecules).
                        Handler(() => { MoleculesCollectionChanged.Throw(this, EventArgs.Empty); });

                    EventsSource.EditSubscriptionsFor(_currentAnimationStep).
                        AfterMethodCall<Molecule>((m) => _currentAnimationStep.AddMolecule(null)).
                        AfterMethodCall<Molecule>((m) => _currentAnimationStep.RemoveMolecule(null)).
                        Handler(() =>
                        {
                            MoleculeAdded.Throw(this, new EventArg<Molecule>(null));
                            MoleculesCollectionChanged.Throw(this, EventArgs.Empty);
                        });
                }

               CurrentAnimationStepChanged.Throw(this, EventArgs.Empty);
               MoleculesCollectionChanged.Throw(this, EventArgs.Empty);
            }
        }

        public Molecule CurrentMolecule
        {
            get { return _currentMolecule; }
            set 
            {
                if(_currentMolecule != null)
                {
                    EventsSource.EditSubscriptionsFor(_currentMolecule)
                        .RemoveHandler(ThrowCurrentMoleculeStructureChanged);

                    EventsSource.EditSubscriptionsFor(_currentMolecule)
                        .RemoveHandler(ThrowCurrentMoleculeZMatrixChanged);

                    EventsSource.EditSubscriptionsFor(_currentMolecule)
                        .RemoveHandler(ThrowCurrentMoleculeTransformMatrixChanged);
                }

                _currentMolecule = value;

                if(_currentMolecule != null)
                {
                    

                    EventsSource.EditSubscriptionsFor(_currentMolecule).
                        AfterPropertySet(() => _currentMolecule.Atoms).
                        AfterPropertySet(() => _currentMolecule.Links).
                        AfterMethodCall<Atom>((a) => _currentMolecule.AddAtom(null)).
                        AfterMethodCall<Atom>((a) => _currentMolecule.RemoveAtom(null)).
                        AfterMethodCall<Link>((a) => _currentMolecule.AddLink(null)).
                        AfterMethodCall<Link>((a) => _currentMolecule.RemoveLink(null)).
                        Handler(ThrowCurrentMoleculeStructureChanged);

                    EventsSource.EditSubscriptionsFor(_currentMolecule).
                        AfterPropertySet(() => _currentMolecule.MoleculeZMatrix).
                        Handler(ThrowCurrentMoleculeZMatrixChanged);

                    EventsSource.EditSubscriptionsFor(_currentMolecule).
                        AfterPropertySet(() => _currentMolecule.TransformMatrix).
                        Handler(ThrowCurrentMoleculeTransformMatrixChanged);
                }
                CurrentMoleculeChanged.Throw(this,EventArgs.Empty); 
            }
        }

        private void ThrowCurrentMoleculeTransformMatrixChanged()
        {
            CurrentMoleculeTransformMatrixChanged.Throw(this, EventArgs.Empty);
        }

        private void ThrowCurrentMoleculeStructureChanged()
        {
            CurrentMoleculeStructureChanged.Throw(this, EventArgs.Empty);
        }

        private void ThrowCurrentMoleculeZMatrixChanged()
        {
            CurrentMoleculeZMatrixChanged.Throw(this, EventArgs.Empty);
        }

        public event EventHandler CurrentAnimationChanged;
        public event EventHandler CurrentAnimationStepChanged;
        public event EventHandler CurrentAnimationStepsChanged;
        public event EventHandler CurrentAnimationStepPercentChanged;
        public event EventHandler CurrentMoleculeChanged;
        public event EventHandler CurrentMoleculeStructureChanged;
        public event EventHandler CurrentMoleculeZMatrixChanged;
        public event EventHandler CurrentMoleculeTransformMatrixChanged;
        public event EventHandler<EventArg<Molecule>> MoleculeAdded;
        public event EventHandler<EventArg<Molecule>> MoleculeRemoved;
        public event EventHandler MoleculesCollectionChanged;

        public void CurrentMoleculeStructureWasModified()
        {
            CurrentMoleculeStructureChanged.Throw(this,EventArgs.Empty);    
        }

        public void CurrentMoleculeZMatrixWasModified()
        {
            CurrentMoleculeZMatrixChanged.Throw(this,EventArgs.Empty);
        }
    }
}